/*
 *
 *  Copyright (C) 2012-2024
 *  All rights reserved, Designed By 杭州连线客信息技术有限公司
 *  注意：
 *  本软件为杭州连线客信息技术有限公司开发研制，未经购买不得使用
 *  购买后可获得全部源代码（禁止转卖、分享、上传到码云、github等开源平台）
 *  一经发现盗用、分享等行为，将追究法律责任，后果自负
 *
 */

package com.lxk.pay.alipay;

import cn.hutool.core.util.StrUtil;
import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.domain.*;
import com.alipay.api.request.AlipayFundTransUniTransferRequest;
import com.alipay.api.response.AlipayFundTransUniTransferResponse;
import com.alipay.api.response.AlipayTradeAppPayResponse;
import com.alipay.api.response.AlipayTradeQueryResponse;
import com.alipay.api.response.AlipayTradeRefundResponse;
import com.ijpay.alipay.AliPayApi;
import com.ijpay.alipay.AliPayApiConfig;
import com.ijpay.alipay.AliPayApiConfigKit;
import com.ijpay.core.enums.TradeType;
import com.lxk.pay.AbstractPayService;
import com.lxk.pay.alipay.constant.AliConstants;
import com.lxk.pay.model.*;
import com.lxk.service.pay.constants.PayServiceBeanConstants;
import com.lxk.service.pay.enums.PayModelEnum;
import com.lxk.service.setting.api.SettingServiceApi;
import com.lxk.service.setting.response.ChannelAllDto;
import jakarta.annotation.PostConstruct;
import jodd.util.StringUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.SchedulingTaskExecutor;
import org.springframework.stereotype.Service;

import java.io.UnsupportedEncodingException;
import java.math.BigDecimal;
import java.net.URLEncoder;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

@Slf4j
@RequiredArgsConstructor
@Service(PayServiceBeanConstants.ALI_PAY_SERVICE)
public class AliPayService extends AbstractPayService {

    private final SettingServiceApi iPaymsAliPayConfigService;
    private final SchedulingTaskExecutor schedulingTaskExecutor;
    public static Map<String, ChannelAllDto> aliMap = new ConcurrentHashMap<String, ChannelAllDto>();
    ;

    @PostConstruct
    @Override
    public void init() {
        schedulingTaskExecutor.execute(() -> {
            List<ChannelAllDto> paymsAliPayConfigVos = iPaymsAliPayConfigService.aliPayList();
            paymsAliPayConfigVos.forEach(payProperties -> {
                AliPayApiConfig wxConfig = null;
                if (StrUtil.isBlank(payProperties.getAliAppId()) ||
                    StrUtil.isBlank(payProperties.getAliPrivateKey().getValue()) ||
                    StrUtil.isBlank(payProperties.getServerUrl().getValue())) {
                    return;
                }
                try {
                    wxConfig = AliPayApiConfig.builder()
                        .setAppId(payProperties.getAliAppId())
                        .setAppCertPath(payProperties.getAliAppCertPath().getValue())
                        .setAliPayCertPath(payProperties.getAliPayCertPath().getValue())
                        .setAliPayRootCertPath(payProperties.getAliPayRootCertPath().getValue())
                        .setCharset(AliConstants.UTF8)
                        .setPrivateKey(payProperties.getAliPrivateKey().getValue())
                        .setAliPayPublicKey(payProperties.getAliPayPublicKey().getValue())
                        .setServiceUrl(payProperties.getServerUrl().getValue())
                        .setSignType(AliConstants.RSA2)
                        // 证书模式
                        .buildByCert();
                } catch (AlipayApiException e) {
                    wxConfig = AliPayApiConfig.builder()
                        .setAppId(payProperties.getAliAppId())
                        .setAppCertPath(payProperties.getAliAppCertPath().getValue())
                        .setAliPayCertPath(payProperties.getAliPayCertPath().getValue())
                        .setAliPayRootCertPath(payProperties.getAliPayRootCertPath().getValue())
                        .setCharset(AliConstants.UTF8)
                        .setPrivateKey(payProperties.getAliPrivateKey().getValue())
                        .setAliPayPublicKey(payProperties.getAliPayPublicKey().getValue())
                        .setServiceUrl(payProperties.getServerUrl().getValue())
                        .setSignType(AliConstants.RSA2)
                        // 普通模式
                        .build();
                    log.error(e.getMessage());
                }
                AliPayApiConfigKit.putApiConfig(wxConfig);
                aliMap.put(payProperties.getAliAppId(), payProperties);
            });
        });
    }

    @Override
    public PayResultModel pay(PayRequestModel payRequestModel) {
        PayResultModel resultModel = new PayResultModel();
        String tradeType = payRequestModel.getTradeTypeForThird();
        String body = payRequestModel.getBody();
        BigDecimal totalFee = payRequestModel.getTotalFee();
        String outTradeNo = payRequestModel.getOutTradeNo();
        String appId = AliPayApiConfigKit.getAppId();

        String encode = "type=order";
        String subject = "订单";
        try {
            encode = URLEncoder.encode(encode, "utf-8");
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
            resultModel.setSuccess(false);
            resultModel.setMsg("支付宝参数UrlEncode异常");
            return resultModel;
        }
        AlipayClient client = getAlipayClient(payRequestModel.getAppId());
        // h5
        if (TradeType.MWEB.getTradeType().equalsIgnoreCase(tradeType)) {
            AlipayTradeWapPayModel model = new AlipayTradeWapPayModel();
            model.setBody(body);
            model.setSubject(subject);
            model.setTotalAmount(totalFee.toString());
            model.setPassbackParams(encode);
            model.setOutTradeNo(outTradeNo);
            model.setProductCode("QUICK_WAP_PAY");
            try {
                ChannelAllDto aliPayProperties = aliMap.get(appId);
                String wapPayStr = AliPayApi.wapPayStr(client, model, aliPayProperties.getAliRefundUrl().getValue(), aliPayProperties.getAliNotifyUrl().getValue());
                resultModel.setSuccess(true);
                resultModel.addResultInfo("wapPayStr", wapPayStr);
                return resultModel;
            } catch (Exception e) {
                resultModel.setMsg(e.getMessage());
                resultModel.setSuccess(false);
            }
        }
        // h5
        if (StrUtil.equalsIgnoreCase(TradeType.APP.getTradeType(), tradeType)) {
            AlipayTradeAppPayModel model = new AlipayTradeAppPayModel();
            model.setBody(body);
            model.setSubject(subject);
            model.setTotalAmount(totalFee.toString());
            model.setPassbackParams(encode);
            model.setOutTradeNo(outTradeNo);
            model.setProductCode("QUICK_WAP_PAY");
            try {
                ChannelAllDto aliPayProperties = aliMap.get(appId);
                AlipayTradeAppPayResponse appPayResponse = AliPayApi.appPayToResponse(client, model, aliPayProperties.getAliNotifyUrl().getValue());
                resultModel.setSuccess(true);
                resultModel.setAppPayResponse(appPayResponse);
                return resultModel;
            } catch (Exception e) {
                resultModel.setMsg(e.getMessage());
                resultModel.setSuccess(false);
                log.error("支付宝异常：", e);
            }
        }
        return resultModel;
    }

    @Override
    public PayNotifyResultModel payNotify(Map<String, String> params, String appId) {
        return null;
    }

    /**
     * 申请退款
     *
     * @param payRequestModel
     * @return
     */
    @Override
    public RefundResultModel refund(PayRefundModel payRequestModel) {
        RefundResultModel resultModel = new RefundResultModel();
        if (payRequestModel.getRefundFee() == null) {
            resultModel.setSuccess(false);
            resultModel.setMsg("退款金额不能为空");
            return resultModel;
        }
        if (StrUtil.isBlank(payRequestModel.getOutTradeNo())) {
            resultModel.setSuccess(false);
            resultModel.setMsg("商户的订单号不能为空");
            return resultModel;
        }
        resultModel.setSuccess(true);
        String outTradeNo = payRequestModel.getOutTradeNo();
        String tradeNo = payRequestModel.getTradeNo();
        BigDecimal amount = payRequestModel.getRefundFee();
        AlipayTradeRefundModel model = new AlipayTradeRefundModel();
        model.setOutTradeNo(outTradeNo);
        model.setTradeNo(tradeNo);
        model.setRefundAmount(amount.toString());
        model.setRefundReason("正常退款");
        model.setOutRequestNo(payRequestModel.getOutRefundNo());
        AlipayClient client = getAlipayClient(payRequestModel.getAppId());
        try {
            AlipayTradeRefundResponse refundResponse = AliPayApi.tradeRefundToResponse(client, getIsCertModel(payRequestModel.getAppId()), model);
            resultModel.setAppPayResponse(refundResponse);
            if (!AliConstants.RESPONSE_SUCCESS_NUM_CODE.equals(refundResponse.getCode()) && !AliConstants.RESPONSE_SUCCESS.equals(refundResponse.getMsg())) {
                resultModel.setSuccess(false);
                resultModel.setMsg(refundResponse.getSubMsg());
            }
        } catch (AlipayApiException e) {
            resultModel.setSuccess(false);
            resultModel.setMsg(e.getMessage());
        }
        return resultModel;
    }

    public AlipayFundTransUniTransferResponse transferAccounts(String realName, String alipayAccount, BigDecimal closingPrice, String orderSn, Long userId) throws AlipayApiException {
        AlipayFundTransUniTransferRequest request = new AlipayFundTransUniTransferRequest();
        AlipayFundTransUniTransferModel model = new AlipayFundTransUniTransferModel();
        //订单号
        model.setOutBizNo(orderSn);
        //转账金额
        model.setTransAmount(closingPrice.toString());
        //销售产品码。单笔无密转账固定为 TRANS_ACCOUNT_NO_PWD。
        model.setProductCode("TRANS_ACCOUNT_NO_PWD");
        //是否展示付款方别名，可选，收款方在支付宝账单中可见  true：展示别名 false：不展示别名
        model.setBusinessParams("{\"payer_show_name_use_alias\":\"true\"}");
        //转账业务的标题，用于在支付宝用户的账单里显示。
        model.setOrderTitle("订单");
        //业务场景。单笔无密转账固定为 DIRECT_TRANSFER。
        model.setBizScene("DIRECT_TRANSFER");
        Participant payeeInfo = new Participant();
        // 参与方的标识类型，目前支持如下枚举：
        // ALIPAY_USER_ID：支付宝会员的用户 ID，可通过 获取会员信息 能力获取。
        // ALIPAY_LOGON_ID：支付宝登录号，支持邮箱和手机号格式。
        payeeInfo.setIdentityType("ALIPAY_LOGON_ID");
        //当 identity_type=ALIPAY_USER_ID 时，填写支付宝用户 UID。示例值：2088123412341234。
        //当 identity_type=ALIPAY_LOGON_ID 时，填写支付宝登录号。示例值：186xxxxxxxx。
        payeeInfo.setIdentity(alipayAccount);
        //参与方真实姓名。如果非空，将校验收款支付宝账号姓名一致性。
        //当 identity_type=ALIPAY_LOGON_ID 时，本字段必填。若传入该属性，则在支付宝回单中将会显示这个属性
        payeeInfo.setName(realName);
        model.setPayeeInfo(payeeInfo);
        request.setBizModel(model);
        return AliPayApi.certificateExecute(request);
    }

    private AlipayClient getAlipayClient(String appId) {
        AlipayClient alipayClient = null;
        if (StringUtil.isNotEmpty(appId)) {
            alipayClient = AliPayApiConfigKit.getApiConfig(appId).getAliPayClient();
        } else {
            alipayClient = AliPayApiConfigKit.getAliPayApiConfig().getAliPayClient();
        }
        return alipayClient;
    }

    /**
     * 是否证书模式 如果没有配置，默认是证书模式
     *
     * @param appId
     * @return
     */
    private Boolean getIsCertModel(String appId) {
        if (StringUtil.isNotEmpty(appId)) {
            ChannelAllDto config = aliMap.get(appId);
            if (config != null) {
                String payModel = config.getPayMode();
                if (StrUtil.isNotBlank(payModel)) {
                    return PayModelEnum.CERT_MODEL.getCode().equals(payModel);
                }
            }
        }
        return true;
    }

    /**
     * 订单支付状态查询
     *
     * @param requestModel
     * @return
     */
    @Override
    public OrderQueryResultModel orderQuery(OrderQueryRequestModel requestModel) {
        String outTradeNo = requestModel.getOutTradeNo();
        OrderQueryResultModel resultModel = new OrderQueryResultModel();
        AlipayTradeQueryModel model = new AlipayTradeQueryModel();
        model.setOutTradeNo(outTradeNo);
        try {
            AlipayClient client = getAlipayClient(requestModel.getAppId());
            AlipayTradeQueryResponse tradeQueryResponse = AliPayApi.tradeQueryToResponse(client, getIsCertModel(requestModel.getAppId()), model);
            if (AliConstants.RESPONSE_SUCCESS_NUM_CODE.equals(tradeQueryResponse.getCode()) && AliConstants.RESPONSE_SUCCESS.equals(tradeQueryResponse.getMsg())) {
                if (AliConstants.TRADE_SUCCESS.equals(tradeQueryResponse.getTradeStatus())) {
                    resultModel.setSuccess(true);
                    resultModel.setMsg(tradeQueryResponse.getTradeStatus());
                } else {
                    resultModel.setSuccess(false);
                    resultModel.setMsg(tradeQueryResponse.getTradeStatus());
                }
            } else {
                resultModel.setSuccess(false);
                resultModel.setMsg(tradeQueryResponse.getSubMsg());
            }
        } catch (AlipayApiException e) {
            resultModel.setSuccess(false);
            resultModel.setMsg(e.getMessage());
        }
        return resultModel;
    }

}
